package com.zbj.homemade.spring.beans;

import com.zbj.homemade.spring.exception.BeanRegistryException;
import com.zbj.homemade.spring.lifecycle.DisposableBean;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * |                    .  ’   *   ‘  .
 * |               _6                    "     o0000o
 * |  o00o _    .%                         %. o0000000o
 * | o000000o.:                              :(0000000o
 * | o00000os                                  .000000o
 * |  o0000/     <b>不了不了,改需求真的伤身体</>   .000o
 * |    o0o                                       .0o
 * |     y        <b>我认为源代码,就是SkrSkr</>     .
 * |    y                                           ,
 * |   y          <b>小熊猫保佑,代码永不修改</>        ,
 * |   p                            .                 .
 * |   p                           @@.                .
 * |    y                        ;@@@;               .
 * |    \                       ;@@@@;.@.          ,;S
 * |     、                     .@@@@@@;       ,@@@@@
 * |     @\.            .****...*@@@@;     .@@@@@@@@@@@.
 * |    @@@@\.     . @@@@@@@@@@@@@@@;    .@@@@@@@@@@@@@@@.
 * |   @@@@@@@@@.@@@@@@@@@@@@@@@@;   .@@@@@@@@@@@@@@@@@@@@@.
 * |  @@@@@@..@@@@..@@@@@@..@@@@@ .@@...@@@@@..@@..@@@@@..@@.
 * | @@@@@@@@..@..@@@@@@@@@@@@@;.@@@..@..@@@..@@....@@@..@@@@.
 * |@y@@@@@@@@..@@@@@@@@..@@@@i@@@@..@@@..@..@@..@@..@..@@@@n@.
 * |@n@@@@@@@..@@@@@@@@..@@@@@@@@@..@@@@@...@@..@@@@...@@@@@n@@.
 * |@@@@@@@@..@@@@@@@@..@@@@@@@@@..@@@@@@@.@@..@@@@@..@@@@@@@@@@.
 * |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
 *
 * @program: principle
 * @description:
 * @author: Yinn
 * @create: 2019-02-28 17:29
 **/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    /**
     * 单例缓存集合
     */
    private final ConcurrentMap<String, Object> singletons = new ConcurrentHashMap<>(256);

    /**
     * 单例销毁接口 缓存集合（在spring容器关闭时，只有单例的DisposableBean会调用销毁方法 多例的不会）
     */
    private final ConcurrentMap<String, DisposableBean> disposableBeans = new ConcurrentHashMap<>(256);

    /**
     * bean names;
     */
    private List<String> singletonBeanNames = new ArrayList<>();

    @Override
    public void registerSingleton(String beanName, Object singletonObject) {

        //判空
        assert StringUtils.isBlank(beanName) || singletonObject == null;

        if (singletons.containsKey(beanName))
            throw new BeanRegistryException("单例重复,beanName:" + beanName);

        singletons.put(beanName, singletonObject);
        singletonBeanNames.add(beanName);

        if (singletonObject instanceof DisposableBean)
            disposableBeans.put(beanName, (DisposableBean) singletonObject);
    }

    @Override
    public Object getSingleton(String beanName) {
        return singletons.get(beanName);
    }

    @Override
    public boolean containsSingleton(String beanName) {
        return singletons.containsKey(beanName);
    }

    @Override
    public String[] getSingletonNames() {
        return singletonBeanNames.toArray(new String[0]);
    }

    @Override
    public int getSingletonCount() {
        return singletons.size();
    }


    protected void clearSingletonCache() {
        this.singletons.clear();
        this.singletonBeanNames.clear();
        this.disposableBeans.clear();
    }

    protected void removeSingleton(String beanName) {
        this.singletons.remove(beanName);
        this.singletonBeanNames.remove(beanName);
    }


    protected void destroySingleton(String beanName) throws Exception {
        removeSingleton(beanName);
        DisposableBean disposableBean = this.disposableBeans.remove(beanName);

        if (disposableBean != null)
            disposableBean.destory();
    }

    protected void destroy(){

        for (String name: singletonBeanNames){
            try {
                destroySingleton(name);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        clearSingletonCache();
    }


}
